package com.hh.pms.Util;

import com.jcraft.jsch.*;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.system.api.domain.SysFile;
import org.apache.catalina.connector.ClientAbortException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class FileUtil {
    protected static final Logger logger = LoggerFactory.getLogger(FileUtil.class);

    public static final String FILENAME = "D:/rouyi/uploadPath/";

    private static final String HOST = "47.236.30.183";

    private static final String USERNAME = "root";

    private static final String PASSWORD = "clk962464A";

    private static final String REMOTE_FILE_PATH = "/opt/file/";


    public static void downloadFiles(String FILENAME, String file, HttpServletResponse response) {
        try {
            System.out.println("file:" + file);
            // 设置响应头，指定为zip文件
            response.setContentType("application/zip");
            response.setHeader("Content-Disposition", "attachment; filename=files.zip");
            // 设置缓冲区大小
            response.setBufferSize(1024 * 1024); // 1MB缓冲区
            // 创建ZipOutputStream
            ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream());
            //拆分文件名
            String[] fileNames = file.split(",");
            // 将多个文件打包到zip文件中
            for (String fileName : fileNames) {
                String name = StringPathUtils.replaceHttpToNull(fileName);
                System.out.println("name:" + FILENAME + "/" + name);
                Path filePath = Paths.get(FILENAME + "/" + name);
                ZipEntry zipEntry = new ZipEntry(StringPathUtils.subStringLastString(fileName));
                zipOut.putNextEntry(zipEntry);

                // 将文件内容写入ZipOutputStream
                Files.copy(filePath, zipOut);
            }
            // 关闭ZipOutputStream
            zipOut.close();
        } catch (IOException e) {
            logger.debug("downloadFiles Exception",e);
        }
    }

    public static void downloadFiles11(String basePath, String fileNamesStr, HttpServletResponse response) {
        // 参数校验
        if (basePath == null || fileNamesStr == null || fileNamesStr.trim().isEmpty()) {
            sendErrorResponse(response, "参数错误");
            return;
        }

        String[] fileNames = fileNamesStr.split(",");
        if (fileNames.length == 0) {
            sendErrorResponse(response, "没有指定要下载的文件");
            return;
        }

        // 设置响应头
        setupDownloadResponse(response);

        try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
            boolean hasValidFiles = processFilesToZip(basePath, fileNames, zipOut, response);

            if (!hasValidFiles) {
                logger.warn("没有有效的文件可下载");
                if (!response.isCommitted()) {
                    sendErrorResponse(response, "没有找到可下载的文件");
                }
                return;
            }

            zipOut.finish();
            logger.info("文件下载完成，共处理 {} 个文件", fileNames.length);

        } catch (ClientAbortException e) {
            logger.debug("客户端中断下载: {}", e.getMessage());
        } catch (IOException e) {
            logger.error("文件下载IO异常", e);
            if (!response.isCommitted()) {
                sendErrorResponse(response, "下载过程发生错误");
            }
        } catch (Exception e) {
            logger.error("文件下载未知异常", e);
            if (!response.isCommitted()) {
                sendErrorResponse(response, "系统错误");
            }
        }
    }

    private static void setupDownloadResponse(HttpServletResponse response) {
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment; filename=download.zip");
        response.setBufferSize(1024 * 1024); // 1MB缓冲区

        // 禁用缓存
        response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", 0);
    }

    private static boolean processFilesToZip(String basePath, String[] fileNames,
                                             ZipOutputStream zipOut, HttpServletResponse response) throws IOException {
        boolean hasValidFiles = false;

        for (String fileName : fileNames) {
            if (response.isCommitted()) {
                logger.debug("响应已提交，停止处理");
                break;
            }

            String processedName = StringPathUtils.replaceHttpToNull(fileName.trim());
            if (processedName.isEmpty()) {
                continue;
            }

            Path filePath = Paths.get(basePath, processedName);
            if (!isValidFile(filePath)) {
                continue;
            }

            if (addFileToZip(filePath, StringPathUtils.subStringLastString(fileName), zipOut, response)) {
                hasValidFiles = true;
            }
        }

        return hasValidFiles;
    }

    private static boolean isValidFile(Path filePath) {
        if (!Files.exists(filePath)) {
            logger.warn("文件不存在: {}", filePath);
            return false;
        }
        if (!Files.isRegularFile(filePath)) {
            logger.warn("不是常规文件: {}", filePath);
            return false;
        }
        if (!Files.isReadable(filePath)) {
            logger.warn("文件不可读: {}", filePath);
            return false;
        }
        return true;
    }

    private static boolean addFileToZip(Path filePath, String entryName,
                                        ZipOutputStream zipOut, HttpServletResponse response) {
        try {
            ZipEntry zipEntry = new ZipEntry(entryName);
            zipOut.putNextEntry(zipEntry);

            try (InputStream fileInput = Files.newInputStream(filePath)) {
                byte[] buffer = new byte[8192];
                int bytesRead;
                long totalBytes = 0;

                while ((bytesRead = fileInput.read(buffer)) != -1) {
                    zipOut.write(buffer, 0, bytesRead);
                    totalBytes += bytesRead;

                    // 每5MB刷新一次
                    if (totalBytes % (5 * 1024 * 1024) == 0) {
                        zipOut.flush();
                        response.flushBuffer();
                    }

                    // 检查客户端是否断开
                    if (response.isCommitted()) {
                        logger.debug("客户端断开，停止写入文件: {}", entryName);
                        return false;
                    }
                }
            }

            zipOut.closeEntry();
            logger.debug("成功添加文件到ZIP: {}, 大小: {} bytes", entryName, Files.size(filePath));
            return true;

        } catch (IOException e) {
            logger.error("添加文件到ZIP失败: {}", entryName, e);
            return false;
        }
    }

    private static void sendErrorResponse(HttpServletResponse response, String message) {
        try {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message);
        } catch (IOException ex) {
            logger.error("发送错误响应失败", ex);
        }
    }

    public static void RemoteFileDownloader(String file, HttpServletResponse response) {
        JSch jsch = new JSch();
        Session session = null;

        try {
            // Create a session with the remote server
            session = jsch.getSession(USERNAME, HOST, 22);
            session.setPassword(PASSWORD);
            session.setConfig("StrictHostKeyChecking", "no");
            session.connect();

            // Create a ZipOutputStream to write the files as a zip archive
            response.setContentType("application/zip");
            response.setHeader("Content-Disposition", "attachment; filename=files.zip");
            ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream());

            // Iterate through each file and add it to the zip
            String[] remoteFileNames = file.split(",");
            for (String fileName : remoteFileNames) {
                downloadAndAddFileToZip(zipOut, session, fileName);
            }

            // Close the ZipOutputStream
            zipOut.close();

        } catch (JSchException | IOException e) {
            logger.debug("RemoteFileDownloader Exception",e);
        } finally {
            if (session != null && session.isConnected()) {
                session.disconnect();
            }
        }

    }

    private static void downloadAndAddFileToZip(ZipOutputStream zipOut, Session session, String remoteFileName)
            throws JSchException, IOException {
        ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
        channelSftp.connect();

        // Specify the remote file path
        String remoteFilePath = REMOTE_FILE_PATH + remoteFileName;
        System.out.println("remoteFilePath:" + remoteFilePath);
        // Open the remote file as an input stream
        try (InputStream inputStream = channelSftp.get(remoteFilePath)) {
            // Add the file to the zip archive
            ZipEntry zipEntry = new ZipEntry(remoteFileName);
            zipOut.putNextEntry(zipEntry);

            // Copy the file content to the ZipOutputStream
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) > 0) {
                zipOut.write(buffer, 0, bytesRead);
            }

            // Close the ZipEntry
            zipOut.closeEntry();
        } catch (SftpException e) {
            throw new RuntimeException(e);
        } finally {
            // Disconnect the SFTP channel
            channelSftp.disconnect();
        }
    }

    public static R<SysFile> handleFileUpload(MultipartFile[] files) {
        JSch jsch = new JSch();
        Session session = null;

        try {
            // Create a session with the remote server
            session = jsch.getSession(USERNAME, HOST, 22);
            session.setPassword(PASSWORD);
            session.setConfig("StrictHostKeyChecking", "no");
            session.connect();

            // Create an SFTP channel
            ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
            channelSftp.connect();

            // Set the time zone to East Asia Standard Time (Shanghai, Beijing)
            TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
            dateFormat.setTimeZone(timeZone);

            // Get the current date in the "yyyy-MM-dd" format
            String currentDate = dateFormat.format(new Date());

            // Specify the remote directory path for today's date
            String remoteDirectory = REMOTE_FILE_PATH + currentDate + "/";

            // Check if the remote directory exists; if not, create it
            try {
                channelSftp.cd(remoteDirectory);
            } catch (SftpException e) {
                channelSftp.mkdir(remoteDirectory);
                channelSftp.cd(remoteDirectory);
            }

            // Upload each file
            for (MultipartFile file : files) {
                // Specify the remote file path within today's date directory
                String remoteFilePath = remoteDirectory + file.getOriginalFilename();

                // Upload the file
                channelSftp.put(file.getInputStream(), remoteFilePath);
            }
            // Disconnect the SFTP channel
            channelSftp.disconnect();
        } catch (JSchException | IOException | SftpException e) {
            e.printStackTrace();
            // Handle the exception as needed
            return R.fail(500, "文件上传失败");
        } catch (MaxUploadSizeExceededException e) {
            e.printStackTrace();
            return R.fail(501, "文件最大不可超过5MB");
        } finally {
            if (session != null && session.isConnected()) {
                session.disconnect();
            }
        }
        SysFile sysFile = new SysFile();
//        sysFile.setName(FileUtils.getName(url));
//        sysFile.setUrl(url);
        return R.ok(sysFile);
    }

    public static R deleteFile(String fileName) {
        fileName = StringPathUtils.replaceHttpToNull(fileName);
        // 创建Path对象
        Path path = Paths.get(FILENAME + fileName);
        try {

            Files.delete(path);
            R.ok(null,"删除成功！！");
        } catch (Exception e) {
            return R.fail("文件删除失败");
        }
        return R.ok();
    }

}
